﻿#include "metafunction.h"
#include "metainfo.h"
#include "reflectutils.h"

MetaFunction::MetaFunction()
{
    idx = 0;
	localIdx = 0;
	localmeta = NULL;
}

bool MetaFunction::isValid() const
{
    return (bool)meta;
}

int MetaFunction::Index() const
{
    return idx;
}

MetaInfo MetaFunction::EnclosingMetaInfo() const
{
	return MetaInfo(meta.get());
}

std::string MetaFunction::Signature() const
{
    if(!isValid()){
        return "";
    }

    const auto & info = LocalMeta()->GetFunctionInfo(LocalIndex());
	return ReflectUtils::GetSignature(info.Name, info.ArgTypes);
}

std::vector<MetaTypeId> MetaFunction::GetParamTypes() const
{
    if(!isValid()){
        return std::vector<MetaTypeId>();
    }

    const auto & info = LocalMeta()->GetFunctionInfo(LocalIndex());
	return	info.ArgTypes;
}

std::string MetaFunction::GetName() const
{
    if(!isValid()){
        return std::string();
    }

    const auto & info = LocalMeta()->GetFunctionInfo(LocalIndex());
	return info.Name;
}

MetaTypeId MetaFunction::GetReturnType() const
{
	if (!isValid()) {
		return MetaType::BT_None;
	}

    const auto & info = LocalMeta()->GetFunctionInfo(LocalIndex());
	return info.ReturnType;
}

std::vector<std::string> MetaFunction::GetFunctionInfos() const
{
    if(!isValid()){
        return std::vector<std::string>();
    }

    const auto & info = LocalMeta()->GetFunctionInfo(LocalIndex());

	return info.Infos;
}

void MetaFunction::DynamicInvoke(void * target, Variant & r, const VariantList & param_) const
{
	VariantList param = param_;
	const void* p[REX_MAX_PARAM_COUNT];
	void* ret = NULL;

	auto types = GetParamTypes();

	for (auto i = 0; i < types.size(); i++) {
		if (!(p[i] = Variant::BeReadyForParam(param[i], types[i]))) {
			return;
		}
	}

	ret = Variant::BeReadyForReturn(r, GetReturnType());
	
	InvokeImply(target, ret, p);
}

void MetaFunction::UnSafeInvoke(void * target, void * r,const void ** param) const
{
	InvokeImply(target,r,param);
}

void MetaFunction::InvokeImply(void *target,void* r, const void **param) const
{
    if(!isValid()){
        return;
    }

	LocalMeta()->InvokeMetaFunction(target, LocalIndex(), r, param);
}

int MetaFunction::LocalIndex() const
{
	return localIdx;
}

IMetaInfoBackend * MetaFunction::LocalMeta() const
{
	return localmeta;
}

MetaFunction::MetaFunction(IMetaInfoBackend *meta, int idx):MetaFunction()
{
    this->meta = meta? meta->shared_from_this() :NULL;
    this->idx = idx;

	localmeta = IMetaInfoBackend::ToLocalFunction(idx, meta, localIdx);
}
